package m.common.service;

import m.appserver.WebServer;
import m.common.model.HostInfo;
import m.common.model.util.ModelQueryList;
import m.common.netty.HostNettyUtil;
import m.system.RuntimeData;
import m.system.db.DBConnection;
import m.system.exception.MException;
import m.system.netty.NettyClient;
import m.system.netty.NettyMessage;
import m.system.util.FileUtil;
import m.system.util.NumberUtil;
import m.system.util.StringUtil;
import m.system.util.SystemUtil;
import manage.model.FileInfo;

import java.io.File;
import java.util.*;

public class HostInfoService extends Service {
	private static int currentOid=0;
	private static HostInfo currentHost;
	public static HostInfo getCurrentHost(){
		if(null==currentHost){
			currentHost=new HostInfo(RuntimeData.getServerName());
		}
		return currentHost;
	}
	public static String getServerIpport() {
		return getIp(currentHost.getIpport())+":"+currentHost.getServerPort();
	}
	private static void setCurrentHost(HostInfo host) {
		currentHost=host;
		RuntimeData.setHostInfo(currentHost);
		currentOid=Integer.parseInt(host.getOid());
	}
	
	private static Map<String,HostInfo> hostMap= new LinkedHashMap<>();
//	public void clearList(){
//		hostMap=new LinkedHashMap<String,HostInfo>();
//	}
	public List<HostInfo> getList(){
		resetCurrentHostOtherInfo();
		return new ArrayList<>(hostMap.values());
	}
	private static long lastLong= 0L;
	private static String[] ips=new String[] {};
	private static final Random random=new Random();
	/**
	 * 获取当前主机列表的随机ip
	 * 
	 */
	public static String getRandomIP(String other) {
		if(System.currentTimeMillis()-lastLong>5000) {
			lastLong=System.currentTimeMillis();
			List<String> ls= new ArrayList<>();
			for(HostInfo hi : hostMap.values()) {
				if(!hi.getIpport().equals(".")) ls.add("http://"+getIp(hi.getIpport())+":"+hi.getServerPort()+"/");
			}
			if(!StringUtil.isSpace(other)) ls.add(other);
			ips=ls.toArray(new String[] {});
		}
		if(ips.length>0) return ips[random.nextInt(ips.length)];
		else return "";
	}
	/**
	 * 获取ip部分
	 *  ipport
	 * 
	 */
	private static String getIp(String ipport) {
		String ip=ipport;
		if(ip.indexOf("/")==0) ip=ip.substring(1);
		return ip.split(":")[0];
	}
	public static void resetCurrentHostOtherInfo(){
		if(null!=currentHost){
			HostInfo hi=hostMap.get(currentHost.getIpport());
			if(null!=hi){
				if(StringUtil.isSpace(hi.getOsInfo())) {
					hi.setServerName(RuntimeData.getServerName());
					Properties props = System.getProperties();
					hi.setOsInfo(props.getProperty("os.name"));
				}
				double mb = 1024 * 1024 * 1.0;
				hi.setTotalMemory(NumberUtil.round(Runtime.getRuntime().totalMemory()/mb, 2));
				hi.setFreeMemory(NumberUtil.round(Runtime.getRuntime().freeMemory()/mb, 2));
				hi.setMaxMemory(NumberUtil.round(Runtime.getRuntime().maxMemory()/mb, 2));
				hi.setDbUseLinkNum(DBConnection.getUseLinkNum());
				hi.setDbMaxLinkNum(DBConnection.getMaxLinkNum());
			}
		}
	}
	private static final Map<String,Integer> hostOidMap= new HashMap<>();
	/**
	 * 服务端可用
	 */
	private static synchronized int getHostOid(String ip) {
		if(null==hostOidMap.get(ip)) {
			int oid=hostOidMap.size();
			hostOidMap.put(ip, oid);
		}
		return hostOidMap.get(ip);
	}
	/**
	 * 主控初始化自己
	 *  ipport
	 */
	public static void setMainHost(String ipport) {
		HostInfo host=hostMap.get(ipport);
		setHostInfo(ipport, host);
		setCurrentHost(host);
	}
	public static boolean isMainHost() {
		if(currentHost.getIpport().equals(".")) return true;
		else return currentHost.getServerMain().equals("Y");
	}
	public static boolean isMainHost(String ipport) {
		HostInfo hi=hostMap.get(ipport);
		return null != hi && (hi.getIpport().equals(".") || hi.getOid().equals("0"));
	}
	/**
	 * 添加主机信息 服务端调用
	 *  ip
	 *  host
	 */
	public static void setHostInfo(String ipport,HostInfo host) {
		host.setOid(String.valueOf(getHostOid(ipport)));
		if(StringUtil.isSpace(host.getServerMain())){
			setServerMain(host.getServerName());
		}
		hostMap.put(ipport, host);
	}

	/**
	 * 设置服务名称对应的主要服务
	 */
	public static void setServerMain(){
		Set<String> sn=new HashSet<>();
		for(HostInfo hi : hostMap.values()){
			if(!sn.contains(hi.getServerName())){
				setServerMain(hi.getServerName());
				sn.add(hi.getServerName());
			}
		}
	}
	/**
	 * 设置服务名称对应的主要服务
	 */
	public static void setServerMain(String serverName){
		boolean b=true;
		for(HostInfo hi : hostMap.values()){
			if(hi.getServerName().equals(serverName)){
				if(b){
					hi.setServerMain("Y");
					b=false;
				}else {
					hi.setServerMain("N");
				}
			}
		}
	}
	/**
	 * 返回主机map 服务端调用
	 * 
	 */
	public static Map<String, HostInfo> getHostMap() {
		return hostMap;
	}
	/**
	 * 清除超时主机  服务端调用
	 */
	public static List<HostInfo> getTimeoutHost(){
		List<HostInfo> list= new ArrayList<>();
		long time=new Date().getTime();
		for(HostInfo hi : hostMap.values()){
			if(isMainHost(hi.getIpport())) continue;
			if(hi.getLastDate().getTime()<time-15*1000){
				list.add(hi);
			}
		}
		for(HostInfo hi : list) {
			removeHost(hi.getIpport());
		}
		return list;
	}
	/**
	 * 移除指定ip主机信息 服务器调用
	 *  ip
	 */
	public static void removeHost(String ipport) {
		hostMap.remove(ipport);
	}
	/**
	 * 设置主机map 客户端调用
	 *  ipport
	 *  hostMap
	 */
	public static void setHostMap(String ipport,Map<String, HostInfo> hostMap) {
		for(HostInfo host : hostMap.values()) {
			if(host.getIpport().equals(ipport)) {
				setCurrentHost(host);
			}
		}
		HostInfoService.hostMap = hostMap;
	}
	
	public static int getCurrentOid() {
		return currentOid;
	}

	/**
	 * 操作主机  method:stop or reboot, reboot时后两个参数可选
	 */
	public void operHost(String ipport,String method,String fileOid,String param) throws MException {
		HostInfo host=hostMap.get(ipport);
		if(null==host) throw new MException(this.getClass(), "主机不存在");
		sendNettyMsg(method,host.getIpport(),fileOid,param);
		//throw new MException(this.getClass(), host.getIpport());
	}

	/**
	 * 发送主机命令
	 *  method
	 *  ipport
	 *  MException 
	 */
	private void sendNettyMsg(String method,String ipport,String fileOid,String param) throws MException {
		NettyMessage msg=new NettyMessage();
		msg.push("host_method", method);
		msg.push("host_method_ipport", ipport);
		msg.push("host_method_file_oid", fileOid);
		msg.push("host_method_java_param", param);
		NettyClient<NettyMessage> client=HostNettyUtil.getClient();
		if(null!=client) {//客户端
			client.send(msg);
		}else if(null!=HostNettyUtil.getServer()){
			readNettyServerMessage(getCurrentHost().getIpport(), msg);
		}else if(".".equals(ipport)&&getCurrentHost().getIpport().equals(ipport)){//单机模式
			readNettyClientMessage(ipport,msg);
		}else {
			throw new MException(this.getClass(), "服务已断开");
		}
	}
	/**
	 * 服务器端执行
	 *  msg
	 */
	public static void readNettyServerMessage(String ipport, NettyMessage msg) {
		String method=StringUtil.noSpace(msg.get(String.class,"host_method"));
		if("stop".equals(method)) {
			String method_ipport=msg.get(String.class,"host_method_ipport");
			if(getCurrentHost().getIpport().equals(method_ipport)) {
				stop();
			}else {
				HostNettyUtil.getServer().send(method_ipport, msg);
			}
		}else if("reboot".equals(method)) {
			String method_ipport=msg.get(String.class,"host_method_ipport");
			if(getCurrentHost().getIpport().equals(method_ipport)) {
				reboot(msg.get(String.class,"host_method_file_oid"),msg.get(String.class,"host_method_java_param"));
			}else {
				HostNettyUtil.getServer().send(method_ipport, msg);
			}
		}
	}

	/**
	 * 客户端执行
	 *  ipport
	 *  msg
	 */
	public static void readNettyClientMessage(String ipport, NettyMessage msg) {
		String method=StringUtil.noSpace(msg.get(String.class,"host_method"));
		if("stop".equals(method)) {//执行停止
			stop();
		}else if("reboot".equals(method)) {//重启
			reboot(msg.get(String.class,"host_method_file_oid"),msg.get(String.class,"host_method_java_param"));
		}
	}
	private static void stop() {
		WebServer.stop();//停止web服务
	}
	private static void reboot(String fileOid,String param) {
		HostInfo host=getCurrentHost();
		try {
			if(!StringUtil.isSpace(fileOid)) {
				FileInfo fi=ModelQueryList.getModel(FileInfo.class, fileOid, "*");
				if(!fi.getName().endsWith(".jar")) throw new MException(HostInfoService.class, "升级文件格式错误");
				SystemUtil.println("升级文件：",RuntimeData.getPublicWeb()+fi.getFilePath());
				File file=new File(RuntimeData.getPublicWeb()+fi.getFilePath());
				if(file.exists()) {
					FileUtil.deleteFile(RuntimeData.getClassPath()+fi.getName());//删除已存在的文件
					FileUtil.writeFile(RuntimeData.getClassPath()+fi.getName(), file);//写入升级文件
					host.setJarName(fi.getName());
				}else {
					throw new MException(HostInfoService.class, "升级文件不存在");
				}
			}
			String javaParam=StringUtil.noSpace(param);
			if(!StringUtil.isSpace(host.getJarName())) {
				stop();//停止web服务
				if(host.getOsInfo().contains("Windows")) {
					Runtime.getRuntime().exec("java "+javaParam+" -jar "+host.getJarName()+" "+host.getServerPort());
				}else if(host.getOsInfo().contains("Linux")) {
					Runtime.getRuntime().exec("nohup java "+javaParam+" -jar "+host.getJarName()+" "+host.getServerPort()+" >log.txt &");
				}
			}
		} catch (Exception e) {
			host.setError(e.getMessage());
			e.printStackTrace();
		}
	}
}
